#include "signuploginwidget.h"
#include "ui_signuploginwidget.h"
#include <QMessageBox>
#include <QHostAddress>
#include <QCryptographicHash>

SignupLoginWidget::SignupLoginWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::SignupLoginWidget)
    , m_pTcpSocket(new QTcpSocket(this))
    , m_buffer()
    , m_packet()
{
    setWindowTitle("用户注册/登录");
    resize(600, 480);

    connect(m_pTcpSocket, &QTcpSocket::connected, [=]() {
        ui->setupUi(this);
    });

    // 处理服务器传来的响应报文
    connect(m_pTcpSocket, &QTcpSocket::readyRead, [=]() {
        qDebug() << "readyRead";
        // 接收完整的Packet
        clearPacket();
        while (m_packet.type == -1) {
            clearPacket();
            readPacket();
        }
        qDebug() << "Read packet finish";
        qDebug() << "type:" << m_packet.type << "len:" << m_packet.length << "msg:" << m_packet.msg;

        if (m_packet.type == TASK_SIGNUP_SECTION1_RESP_ERROR || m_packet.type == TASK_SIGNUP_SECTION2_RESP_ERROR) {
            qCritical() << m_packet.msg;
            QMessageBox::warning(this, "Error", "Signup failed");
            return;
        }
        if (m_packet.type == TASK_LOGIN_SECTION1_RESP_ERROR || m_packet.type == TASK_LOGIN_SECTION2_RESP_ERROR) {
            qCritical() << m_packet.msg;
            QMessageBox::warning(this, "Error", "Login failed");
            return;
        }
        if (m_packet.type == TASK_SIGNUP_SECTION1_RESP_OK || m_packet.type == TASK_LOGIN_SECTION1_RESP_OK) {
            // 从密码行文本编辑框中获取密码，从服务器的响应报文中获取setting，生成setting$MD5哈希值密文
            QString encryptedPassword = genEncryptedPassword();
            // 拼接用户名长度+用户名+密文长度+密文
            QString userName = ui->userNameLineEdit->text();
            QByteArray msg = concatLenValueLenVal(userName, encryptedPassword);
//            qDebug() << "msg:" << msg.toHex(); // 以十六进制形式打印
            qDebug() << "msg:" << msg;
            // 将拼接好的用户名+密文发送给服务器
            if (m_packet.type == TASK_SIGNUP_SECTION1_RESP_OK) {
                sendTLV(TASK_SIGNUP_SECTION2, sizeof(int) + userName.size() + sizeof(int) + encryptedPassword.size(), msg);
            }
            if (m_packet.type == TASK_LOGIN_SECTION1_RESP_OK) {
                sendTLV(TASK_LOGIN_SECTION2, sizeof(int) + userName.size() + sizeof(int) + encryptedPassword.size(), msg);
            }
            return;
        }
        if (m_packet.type == TASK_SIGNUP_SECTION2_RESP_OK) {
            qInfo() << m_packet.msg;
            QMessageBox::information(this, "Info", "Signup success");
            return;
        }
        if (m_packet.type == TASK_LOGIN_SECTION2_RESP_OK) {
            qInfo() << m_packet.msg;
            QMessageBox::information(this, "Info", "Login success");
            return;
        }
    });

    m_pTcpSocket->connectToHost(QHostAddress("192.168.109.128"), 8000);
}

SignupLoginWidget::~SignupLoginWidget()
{
    delete ui;
}

void SignupLoginWidget::sendTLV(TaskType type, int len, QByteArray msg)
{
    if (!m_pTcpSocket->isOpen() || !m_pTcpSocket->isWritable()) {
        QMessageBox::warning(this, "Error", "TcpSocket is not connected");
        return;
    }
    if (msg.isEmpty()) {
        QMessageBox::warning(this, "Error", "UserName or password is empty");
        return;
    }

    QByteArray tlv;
    // 将4字节type写入tlv中
    tlv.append(reinterpret_cast<const char *>(&type), sizeof(int));
    // 将4字节len写入tlv中
    tlv.append(reinterpret_cast<const char *>(&len), sizeof(int));
    // 将QString转为Utf-8编码的字节数组，写入tlv中
    qDebug() << msg.toHex();
    tlv.append(msg);

    // 发送tlv
    sendn(tlv, sizeof(int) * 2 + len);
    m_pTcpSocket->flush();
}

void SignupLoginWidget::readPacket()
{
    // 接收服务器发来的所有数据，存入buf中
    m_buffer.append(m_pTcpSocket->readAll());
//    qDebug() << "buffer:" << m_buffer;

    if (m_buffer.size() >= static_cast<int>(sizeof(int) * 2)) {
        // 从buf中解析获取Packet

        // 获取4字节type
        memcpy(&m_packet.type, m_buffer.constData(), sizeof(int));
        // 获取4字节len
        memcpy(&m_packet.length, m_buffer.constData() + sizeof(int), sizeof(int));

        // 若buf中的数据不满足所需的len个字节，清空Packet并返回
        if (m_buffer.size() < static_cast<int>(sizeof(int) * 2) + m_packet.length) {
            clearPacket();
            return;
        }

        // 从buf的第9个字节开始获取len字节消息内容，并从Utf-8编码字符数组转为QString
        m_packet.msg = QString::fromUtf8(m_buffer.mid(sizeof(int) * 2, m_packet.length));

        // buf移到当前Packet末尾的下一个字节处
        m_buffer.remove(0, sizeof(int) * 2 + m_packet.length);
    }
}

void SignupLoginWidget::clearPacket()
{
    m_packet.type = -1;
    m_packet.length = 0;
    m_packet.msg = QString();
}

int SignupLoginWidget::sendn(QByteArray buf, int len)
{
    int left = len;
    const char *pCurr = buf.constData();
    while (left > 0) {
        int ret = m_pTcpSocket->write(pCurr, len);
        if (ret == -1) {
            QMessageBox::critical(this, "Error", "Tcp write failed");
            return len - left;
        }
        pCurr += ret;
        left -= ret;
    }
    return len;
}

QString SignupLoginWidget::genEncryptedPassword()
{
     // 获取setting
     QString setting = m_packet.msg;
     if (setting.isEmpty()) {
         qCritical() << "Setting is empty";
         if (m_packet.type == TASK_SIGNUP_SECTION1_RESP_OK) {
             QMessageBox::warning(this, "Error", "Signup failed");
         }
         else {
             QMessageBox::warning(this, "Error", "Login failed");
         }
         return QString();
     }
     // 获取密码
     QString password = ui->passwordLineEdit->text();
     qDebug() << "password:" << password;
     // 密码+setting生成MD5密文
     QString encrypted = QCryptographicHash::hash((password + setting).toUtf8(), QCryptographicHash::Md5).toHex();
     QString encryptedPassword = setting + "$" + encrypted;
     qDebug() << "encryptedPassword:" << encryptedPassword;
     return encryptedPassword;
}

QByteArray SignupLoginWidget::concatLenValueLenVal(QString str1, QString str2)
{
    QByteArray msg;
    int length1 = static_cast<int>(str1.size());
    msg.append(reinterpret_cast<const char *>(&length1), sizeof(int)); // str1长度
    msg.append(str1.toUtf8()); // str1
    int length2 = static_cast<int>(str2.size());
    msg.append(reinterpret_cast<const char *>(&length2), sizeof(int)); // str2长度
    msg.append(str2.toUtf8()); // str2
    return msg;
}

void SignupLoginWidget::on_signupPushButton_clicked()
{
    // 发送用户名
    QString userName = ui->userNameLineEdit->text();
    qDebug() << "userName:" << userName;
    sendTLV(TASK_SIGNUP_SECTION1, static_cast<int>(userName.size()), userName.toUtf8());
    qDebug() << "Send userName success";
}

void SignupLoginWidget::on_loginPushButton_clicked()
{
    // 发送用户名
    QString userName = ui->userNameLineEdit->text();
    qDebug() << "userName:" << userName;
    sendTLV(TASK_LOGIN_SECTION1, static_cast<int>(userName.size()), userName.toUtf8());
    qDebug() << "Send userName success";
}
